package persistence

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"

	"xiaoniu-registry/internal/cache"
	"xiaoniu-registry/internal/config"
	"xiaoniu-registry/pkg"
)

// RegistryData 注册中心数据结构
type RegistryData struct {
	Services  []string                   `json:"services"`
	Instances map[string][]*pkg.Instance `json:"instances"`
	Timestamp time.Time                  `json:"timestamp"`
	Version   string                     `json:"version"`
}

// PersistenceManager 持久化管理器
type PersistenceManager struct {
	dataDir   string
	backupDir string
	mutex     sync.RWMutex
	enabled   bool
	interval  time.Duration
	stopChan  chan struct{}
}

var (
	manager *PersistenceManager
	once    sync.Once
)

// InitPersistence 初始化持久化管理器
func InitPersistence(cfg *config.Config) *PersistenceManager {
	once.Do(func() {
		manager = &PersistenceManager{
			dataDir:   cfg.Persistence.DataDir,
			backupDir: cfg.Persistence.BackupDir,
			enabled:   cfg.Persistence.Enabled,
			interval:  cfg.Persistence.Interval,
			stopChan:  make(chan struct{}),
		}

		// 创建数据目录
		if err := os.MkdirAll(manager.dataDir, 0755); err != nil {
			log.Printf("Failed to create data directory: %v", err)
		}
		if err := os.MkdirAll(manager.backupDir, 0755); err != nil {
			log.Printf("Failed to create backup directory: %v", err)
		}

		// 启动时加载数据
		if manager.enabled {
			manager.LoadData()
			// 启动定期保存
			go manager.startPeriodicSave()
		}
	})
	return manager
}

// GetManager 获取持久化管理器实例
func GetManager() *PersistenceManager {
	return manager
}

// SaveData 保存数据到文件
func (pm *PersistenceManager) SaveData() error {
	if !pm.enabled {
		return nil
	}

	pm.mutex.Lock()
	defer pm.mutex.Unlock()

	// 收集当前数据
	services := cache.QueryServiceList()
	instances := make(map[string][]*pkg.Instance)
	serviceNames := make([]string, 0, len(services))

	for _, service := range services {
		serviceNames = append(serviceNames, service.Name)
		instances[service.Name] = cache.QueryInstancesByServiceName(service.Name)
	}

	data := RegistryData{
		Services:  serviceNames,
		Instances: instances,
		Timestamp: time.Now(),
		Version:   "1.0.0",
	}

	// 序列化数据
	jsonData, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal data: %v", err)
	}

	// 写入临时文件
	tempFile := filepath.Join(pm.dataDir, "registry.tmp")
	if err := ioutil.WriteFile(tempFile, jsonData, 0644); err != nil {
		return fmt.Errorf("failed to write temp file: %v", err)
	}

	// 原子性替换
	dataFile := filepath.Join(pm.dataDir, "registry.json")
	if err := os.Rename(tempFile, dataFile); err != nil {
		return fmt.Errorf("failed to rename temp file: %v", err)
	}

	// 创建备份
	pm.createBackup(dataFile)

	log.Printf("Registry data saved successfully with %d services and %d total instances",
		len(services), pm.countTotalInstances(instances))
	return nil
}

// LoadData 从文件加载数据
func (pm *PersistenceManager) LoadData() error {
	if !pm.enabled {
		return nil
	}

	pm.mutex.RLock()
	defer pm.mutex.RUnlock()

	dataFile := filepath.Join(pm.dataDir, "registry.json")
	if _, err := os.Stat(dataFile); os.IsNotExist(err) {
		log.Println("No existing registry data file found, starting fresh")
		return nil
	}

	// 读取文件
	jsonData, err := ioutil.ReadFile(dataFile)
	if err != nil {
		return fmt.Errorf("failed to read data file: %v", err)
	}

	// 反序列化数据
	var data RegistryData
	if err := json.Unmarshal(jsonData, &data); err != nil {
		return fmt.Errorf("failed to unmarshal data: %v", err)
	}

	// 恢复数据到缓存
	loadedServices := 0
	loadedInstances := 0

	for _, serviceName := range data.Services {
		cache.AddNewService(serviceName)
		loadedServices++

		if instances, exists := data.Instances[serviceName]; exists {
			for _, instance := range instances {
				// 恢复实例，但不启动心跳（需要实例重新注册）
				cache.AddInstance(serviceName, instance.Ip, instance.Port, instance.Weight)
				loadedInstances++
			}
		}
	}

	log.Printf("Registry data loaded successfully: %d services, %d instances from %v",
		loadedServices, loadedInstances, data.Timestamp)
	return nil
}

// createBackup 创建备份文件
func (pm *PersistenceManager) createBackup(dataFile string) {
	backupFile := filepath.Join(pm.backupDir,
		fmt.Sprintf("registry_%s.json", time.Now().Format("20060102_150405")))

	if err := pm.copyFile(dataFile, backupFile); err != nil {
		log.Printf("Failed to create backup: %v", err)
	} else {
		log.Printf("Backup created: %s", backupFile)
	}

	// 清理旧备份（保留最近10个）
	pm.cleanOldBackups()
}

// copyFile 复制文件
func (pm *PersistenceManager) copyFile(src, dst string) error {
	data, err := ioutil.ReadFile(src)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(dst, data, 0644)
}

// cleanOldBackups 清理旧备份文件
func (pm *PersistenceManager) cleanOldBackups() {
	files, err := ioutil.ReadDir(pm.backupDir)
	if err != nil {
		return
	}

	// 只保留最近的10个备份文件
	if len(files) > 10 {
		// 按修改时间排序，删除最旧的文件
		for i := 0; i < len(files)-10; i++ {
			oldFile := filepath.Join(pm.backupDir, files[i].Name())
			if err := os.Remove(oldFile); err != nil {
				log.Printf("Failed to remove old backup %s: %v", oldFile, err)
			}
		}
	}
}

// startPeriodicSave 启动定期保存
func (pm *PersistenceManager) startPeriodicSave() {
	ticker := time.NewTicker(pm.interval)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			if err := pm.SaveData(); err != nil {
				log.Printf("Periodic save failed: %v", err)
			}
		case <-pm.stopChan:
			log.Println("Stopping periodic save")
			return
		}
	}
}

// Stop 停止持久化管理器
func (pm *PersistenceManager) Stop() {
	if pm.enabled {
		// 最后保存一次数据
		if err := pm.SaveData(); err != nil {
			log.Printf("Final save failed: %v", err)
		}
		close(pm.stopChan)
		log.Println("Persistence manager stopped")
	}
}

// countTotalInstances 计算总实例数
func (pm *PersistenceManager) countTotalInstances(instances map[string][]*pkg.Instance) int {
	total := 0
	for _, instanceList := range instances {
		total += len(instanceList)
	}
	return total
}

// GetStats 获取持久化统计信息
func (pm *PersistenceManager) GetStats() map[string]interface{} {
	stats := map[string]interface{}{
		"enabled":    pm.enabled,
		"data_dir":   pm.dataDir,
		"backup_dir": pm.backupDir,
		"interval":   pm.interval.String(),
	}

	if pm.enabled {
		// 检查数据文件状态
		dataFile := filepath.Join(pm.dataDir, "registry.json")
		if info, err := os.Stat(dataFile); err == nil {
			stats["last_save"] = info.ModTime()
			stats["file_size"] = info.Size()
		}

		// 统计备份文件数量
		if files, err := ioutil.ReadDir(pm.backupDir); err == nil {
			stats["backup_count"] = len(files)
		}
	}

	return stats
}
